Packer+AnsibleによるAMIの作成
渡辺です。
クラスメソッドのAWSチームは基本的に自分が使いやすいツールを選択するので統一されていません。 が、誰からいいね!と推しはじめると流行していく、そんな雰囲気です。
Ansible
AnsibleはChefなどと同じ構成管理ツールのひとつで、AWSチームではAnsibleを使う人が多くなってきました。Ansibleの紹介は、構成管理ツール Ansibleを使ってみるを読んでみてください。
Packer
Packerも広義には構成管理ツールですが、マシンイメージを作成するためのツールです。 AWSで言えばEBSマシンイメージを作るのに利用できます。 Packerについては、PackerでAmazon LinuxのAMI(Amazon Machine Image)を作成するを参照ください。
PackerでAnsibleによる構成管理
Packerはマシンイメージを作成するためのツールで簡単なスクリプトなどを実行することができます。 しかし、複雑な構成管理となるとChefやAnsibleなどのように多機能というわけではなく、シェルスクリプト地獄に陥ってしまうのが難点です。 そもそもシェルスクリプトだけで構成管理が可能であれば、EC2のUserDataを使えば済むわけなので、わざわざPackerを利用することもないでしょう。
builderとprovisioner
PackerではAWSのイメージを作る部分はbuilderと呼びます。 builderはAMI以外でも、VirtualBoxなどの仮想マシンイメージを作るのに利用することができます。
一方、構築用の定義はprovisionerに定義します。 シェルスクリプトを実行するのであれば、shell provisionerを指定します。 shell provisionerの他にもchefやansibleもprovisionerとして対応しているため、好きな構成管理ツールで構成を定義し、Packerでイメージを作るという使い方が出来るわけです。
というわけで、Ansibleで構成管理を行いAMIを作成してみました。
AnsibleのPlaybookの作成
AnsibleのPlaybookは、構成の定義ファイルです。 Apacheとmysql クライアントをインストールし、起動時にApacheを起動する簡単な定義ファイルを作成しました。
setup.yml
- hosts: all sudo: yes tasks: - name: install Apache24 and mysql client yum: pkg={{item}} state=installed with_items: - mysql - httpd24 - name: enable httpd service service: name=httpd enabled=yes
ポイントとしては、ec2-userでAnsibleが実行されるため、sudoをyesに設定することです。
Packerのテンプレートの作成
続けてPackerのテンプレートを作成します。
web.json
{ "variables": { "aws_access_key": "", "aws_secret_key": "" }, "builders": [{ "type": "amazon-ebs", "access_key": "{{user `aws_access_key`}}", "secret_key": "{{user `aws_secret_key`}}", "region": "ap-northeast-1", "source_ami": "ami-4985b048", "instance_type": "t2.small", "ssh_username": "ec2-user", "ssh_timeout": "5m", "ami_name": "Web_{{isotime | clean_ami_name}}" }], "provisioners": [{ "type": "shell", "inline": [ "sudo yum -y update", "sudo yum -y --enablerepo=epel install ansible" ] },{ "type": "ansible-local", "playbook_file": "setup.yml" }] }
buildersにamazon-ebsを指定し、PackerがAnsibleを使い実行する環境を定義します。 Ansibleはlocalで実行する、つまりEC2インスタンスで実行され自分自身を構成する方式です。 通常のAnsibleのようにローカル環境からSSHで接続して実行する形式は現時点ではサポートされていないので注意してください。
また、AWSのアクセスキーとシークレットキーを定義する必要がありますが、このテンプレートファイルはgitなどでバージョン管理するため生情報を埋め込んではいけません。 PackerのVariablesの機能を利用し、外部のVariableファイルに定義してください。 Variableファイルは.gitignoreなどでバージョン管理外としておきます。
variables.json
{ "aws_access_key": "[YOUR_AWS_ACCESS_KEY]", "aws_secret_key": "[YOUR_AWS_SECRET_KEY]" }
provisionersには構成管理に必要な定義を記述していきます。 ここはansible-localを指定すれば良いのですが、実行するEC2インスタンスにAnsibleがインストールされていないとコケてしまうため、ansibleのインストールはPackerのshell provisionerでインストールしておきます。 ansible-localでの設定は、先ほど作成したsetup.ymlを指定するだけです、簡単ですね。
ビルド
ビルドはPackerコマンドで、Variableファイルをオプションで指定して実行します。
$ packer build -var-file=variables.json web.json
ビルドがはじまると、AWS環境にEC2インスタンスが作成され、環境構築がはじまります。 はじめにshell provisionerでAnsibleがインストールされ、後続のansible-local provisionerで必要なミドルウェアや環境設定が行われていきます。 構築が完了すると、AMI(マシンイメージ)が作成され、構築用に作成されたEC2インスタンスは破棄されます。
$ packer build -var-file=variables.json web.json amazon-ebs output will be in this color. ==> amazon-ebs: Inspecting the source AMI... ==> amazon-ebs: Creating temporary keypair: packer 548e8a9c-cbff-a528-8933-c274c1a5666e ==> amazon-ebs: Creating temporary security group for this instance... ==> amazon-ebs: Authorizing SSH access on the temporary security group... ==> amazon-ebs: Launching a source AWS instance... amazon-ebs: Instance ID: i-72c8e36b ==> amazon-ebs: Waiting for instance (i-72c8e36b) to become ready... ==> amazon-ebs: Waiting for SSH to become available... ==> amazon-ebs: Connected to SSH! ==> amazon-ebs: Provisioning with shell script: /var/folders/k4/k385q7zs26z3h5ngv4d1rwk80000gn/T/packer-shell972002311 (中略) amazon-ebs: Complete! ==> amazon-ebs: Provisioning with Ansible... amazon-ebs: Creating Ansible staging directory... amazon-ebs: Creating directory: /tmp/packer-provisioner-ansible-local amazon-ebs: Uploading main Playbook file... amazon-ebs: Uploading inventory file... (中略) ==> amazon-ebs: Stopping the source instance... ==> amazon-ebs: Waiting for the instance to stop... ==> amazon-ebs: Creating the AMI: Web_2014-12-15T07-15-40Z amazon-ebs: AMI: ami-XXXXXXXXX ==> amazon-ebs: Waiting for AMI to become ready... ==> amazon-ebs: Terminating the source AWS instance... ==> amazon-ebs: Deleting temporary security group... ==> amazon-ebs: Deleting temporary keypair... Build 'amazon-ebs' finished. ==> Builds finished. The artifacts of successful builds are: --> amazon-ebs: AMIs were created:
最後にAMIのイメージIDが表示されるのでメモしましょう。
なお、構築を何度もしているとこのようにterminatedのインスタンスまみれになりますw
AMIの活用
Packerを利用するパターンではインスタンスを予め作りAMIとして保存してしまうため、CloudFormationとの相性が抜群に良いです。 CloudFormationで面倒なUserDataやCloudInitを利用せずに、構成管理は専門のツールを使うワケです。 また、AMIはバージョンアップ時にも残しておくことで、EC2インスタンスのバージョンも簡単に管理できますね。